﻿#include "WasReader.h"

////////////////////////////////////////////////////////////////////////// sSpFrame
bool sSpFrame::isValid() const
{
	return w > 0 && h > 0;
}


////////////////////////////////////////////////////////////////////////// sSpInfo
sSpInfo::~sSpInfo()
{
	ccc_delete_array(frames);
}

void sSpInfo::load(const sInfo& info)
{
	directionsCount = info.directionsCount;
	framesCountPerDirection = info.framesCountPerDirection;
	width = info.width;
	height = info.height;
	kx = info.kx;
	ky = info.ky;
	framesCount = directionsCount * framesCountPerDirection;
}



void sSpInfo::load(const char *ptr)
{
	ushort head = *(ushort*)(ptr + 2);
	sSpInfo::sInfo inf;
	memcpy(&inf, ptr + 4, 12);
	load(inf);

	head += 4;
	ptr += head;
	//	palette = (s565*)ptr;
	auto offsets = (uint*)(ptr + 512);
	int total = framesCount;
	frames = new sSpFrame[total];

	auto frame = frames;
	auto offs = offsets;
	for (int k = 0; k < total; ++k, ++frame, ++offs)
	{
		if (*offs == 0)
		{
			continue;
		}
		memcpy((sSpFrame*)frame, (ptr + *offs), 16);
	}

}

bool sSpInfo::isValid() const
{
	return width > 0 && height > 0 && directionsCount > 0 && framesCountPerDirection > 0 && frames != nullptr;
}



////////////////////////////////////////////////////////////////////////// sDecode
sDecode::sDecode()
{
}

sDecode::~sDecode()
{
	ccc_delete_array(indexs);
	ccc_delete_array(alphas);
	ccc_delete_array(normal565);
}

bool sDecode::isValid() const
{
	return width > 0 && height > 0 && indexs != nullptr && alphas != nullptr;
}


void sDecode::decode(const uchar *pHead, uint offs)
{
	if (isDecoded)
	{
		return;
	}
	isDecoded = true;

	static int size, size2; size = width * height;
	indexs = new uchar[size];
	alphas = new uchar[size];
	memset(alphas, 0, size);


	static uint* pLine; pLine = (uint*)(pHead + offs + 16);
	static decltype(indexs) pIndex, pI; pIndex = indexs;
	static decltype(alphas) pAlpha, pA; pAlpha = alphas;
	static decltype(pHead) ptr;
	static bool isgh, parity; isgh = true; //奇偶性
	uchar dataCheck, dataWait, alphaWait;
	for (int k = 0, ix; k < height; ++k, ++pLine, pIndex += width, pAlpha += width)
	{
		ptr = pHead + offs + *pLine;
		pI = pIndex;
		pA = pAlpha;
		parity = ((k % 2) == 1);
		for (ix = 0; ix < width;)
		{
			dataCheck = *ptr;
			if (dataCheck == 0)// 像素行结束  
			{
				break;
			}
			++ptr;
			switch (dataCheck & 0xC0)
			{
			case 0x00: // Bit7-8=00
				if (isgh && parity)
				{
					isgh = false;
				}
				if (dataCheck & 0x20)// 若Bit6=1
				{
					alphaWait = (dataCheck & 0x1F);// Bit1-5
					if (alphaWait)
					{
						*pI = *ptr;
						*pA = alphaWait;
					}
					++ptr;
					++ix;
					++pI;
					++pA;
				}
				else
				{
					alphaWait = *ptr;
					if (alphaWait)
					{
						size = (dataCheck & 0x1F);
						dataWait = *(ptr + 1);
						size2 = std::min(size, width - ix);
						memset(pI, dataWait, size2);
						memset(pA, alphaWait, size2);
						ix += size;
						pI += size;
						pA += size;
					}
					ptr += 2;

				}
				break;
			case 0x40: // Bit7-8=01
				if (isgh && parity)
				{
					isgh = false;
				}
				size = (dataCheck & 0x3f);
				size2 = std::min(size, width - ix);
				memcpy(pI, ptr, size2);
				memset(pA, 0x20, size2);
				ptr += size;
				ix += size;
				pI += size;
				pA += size;
				break;
			case 0x80: // Bit7-8=10
				if (isgh && parity)
				{
					isgh = false;
				}
				size = (dataCheck & 0x3F);
				dataWait = *ptr;
				++ptr;
				size2 = std::min(size, width - ix);
				memset(pI, dataWait, size2);
				memset(pA, 0x20, size2);
				ix += size;
				pI += size;
				pA += size;
				break;
			default:
				size = (dataCheck & 0x3F);
				if (0 == size)
				{
					ptr += 2;
				}
				else
				{
					ix += size;
					pI += size;
					pA += size;
				}
				break;
			}
		}
	}
	if (isgh)
	{
		pI = indexs;
		pA = alphas;
		for (int k = 0; k < height - 1; k += 2, pI += width * 2, pA += width * 2)
		{
			memcpy(pI + width, pI, width);
			memcpy(pA + width, pA, width);
		}
	}
}


void sDecode::to565(const uchar *indexs, const uchar *alphas, int width, int height, const s565 *palettes, s565 *datas)
{
	static decltype(indexs) pIndex, pI; pIndex = indexs;
	static decltype(alphas) pAlpha, pA; pAlpha = alphas;
	static decltype(palettes) palette; palette = palettes;
	static decltype(datas) pData, pD; pData = datas;

	for (int k = 0; k < height; ++k, pIndex += width, pAlpha += width, pData += width)
	{
		pA = pAlpha;
		pI = pIndex;
		pD = pData;
		for (int i = 0; i < width; ++i, ++pI, ++pA, ++pD)
		{
			if (*pA == 0)
			{
				continue;
			}
			*pD = palette[*pI];
		}
	}
}


const s565* sDecode::get565(const s565* palettes)
{
	auto& p565 = normal565;
	if (p565 == nullptr)
	{
		p565 = new s565[width * height];
		memset(p565, 0, width * height * sizeof(s565));
		to565(indexs, alphas, width, height, palettes, p565);
	}
	return p565;
}




////////////////////////////////////////////////////////////////////////// sDecoderEasy
sDecoderEasy::sDecoderEasy()
{

}

sDecoderEasy::~sDecoderEasy()
{
	ccc_delete_array(decodes);
	ccc_delete_array(ptr);
}


void sDecoderEasy::load(const char *ptrr, const sSpInfo *infoo)
{
	ptr = ptrr;
	info = infoo;
	ushort head = *(ushort*)(ptrr + 2);
	ptrr += head + 4;
	palette = (s565*)ptrr;
	offsets = (uint*)(ptrr + 512);
	if (decodes == nullptr)
	{
		decodes = new sDecode[info->framesCount];
		auto dec = decodes;
		auto frame = info->frames;
		for (int k = info->framesCount - 1; k >= 0; --k, ++frame, ++dec)
		{
			dec->width = frame->w;
			dec->height = frame->h;
		}
	}
}


sDecode* sDecoderEasy::getDecode(int iframe)
{
	auto deco = decodes + iframe;
	deco->decode((const uchar*)palette, *(offsets + iframe));
	if (deco->isValid())
	{
		return deco;
	}
	return nullptr;
}


bool sDecoderEasy::isSnatch(int x, int y, int iframe)
{
	const auto& frame = info->frames + iframe;
	x -= info->kx - frame->x;
	y -= info->ky - frame->y;
	if (x < 0 || y < 0 || x >= frame->w || y >= frame->h)
	{
		return false;
	}
	auto deco = getDecode(iframe);
	if (deco == nullptr)
	{
		return false;
	}
	return *(deco->alphas + (y * frame->w + x)) >= 0x1F;
}


const s565* sDecoderEasy::get565(int iframe)
{
	auto deco = getDecode(iframe);
	if (deco == nullptr)
	{
		return nullptr;
	}
	return deco->get565(palette);
}




////////////////////////////////////////////////////////////////////////// sSpInfo
// WasReader::~WasReader()
// {
// 	ccc_delete_array(frames);
// }
// 
// void WasReader::load(const sInfo& info)
// {
// 	directionsCount = info.directionsCount;
// 	framesCountPerDirection = info.framesCountPerDirection;
// 	width = info.width;
// 	height = info.height;
// 	kx = info.kx;
// 	ky = info.ky;
// 	framesCount = directionsCount * framesCountPerDirection;
// }
// 
// 
// 
// void WasReader::load(const char *ptr)
// {
// 	ushort head = *(ushort*)(ptr + 2);
// 	WasReader::sInfo inf;
// 	memcpy(&inf, ptr + 4, 12);
// 	load(inf);
// 
// 	head += 4;
// 	ptr += head;
// 	//	palette = (s565*)ptr;
// 	auto offsets = (uint*)(ptr + 512);
// 	int total = framesCount;
// 	frames = new sSpFrame[total];
// 
// 	auto frame = frames;
// 	auto offs = offsets;
// 	for (int k = 0; k < total; ++k, ++frame, ++offs)
// 	{
// 		if (*offs == 0)
// 		{
// 			continue;
// 		}
// 		memcpy((sSpFrame*)frame, (ptr + *offs), 16);
// 	}
// 
// }
// 
// WasReader::sFrameData WasReader::getFrameData(int i)
// {
// 
// }
// 
// void WasReader::clearPointer()
// {
// 
// }
// 
// WasReader::~WasReader()
// {
// 
// }
